package com.billionsfinance.hessian.core;

import com.billionsfinance.hessian.annotation.HessianService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.remoting.caucho.HessianProxyFactoryBean;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import java.util.Arrays;
import java.util.List;
import java.util.Set;

/**
 * @fileName: HessianBeanFactory.java
 * @author: WeiHui.Zhang
 * @date: 2016-10-10  16:09
 * @version: v1.0.0
 */
@Component
public class HessianClientBeanFactory implements ApplicationContextAware {

	private static final String defaultSuffix = ".htm";

	/**
	 * 访问地址
	 */
	protected String accessUrl;

	/**
	 * 访问前缀
	 */
	protected String prefix;

	/**
	 * 访问后缀
	 */
	protected String suffix;


	protected String[] packages;

	protected boolean overloadEnabled;

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		Assert.notNull(accessUrl, "远程Hessian访问地址不能为空。");
		String pre = "";
		if (StringUtils.isNotBlank(prefix)) {
			pre = prefix;
		}
		String suf = defaultSuffix;
		if (StringUtils.isNotBlank(suffix)) {
			suf = suffix;
		}
		ConfigurableApplicationContext context = (ConfigurableApplicationContext) applicationContext;
		List<String> asList = Arrays.asList(packages);
		Set<Class<?>> hessianClasses = ClassUtils.getClassesAnnotationWith(asList, HessianService.class);
		for (Class<?> hessianClass : hessianClasses) {
			String simpleName = hessianClass.getSimpleName();
			String name = hessianClass.getName();
			registerBeanDefinition(context, accessUrl + pre + simpleName + suf, name);
		}
	}


	//	<!-- 调用远程接口代理工厂 -->
	//<bean id="addService" class="org.springframework.remoting.caucho.HessianProxyFactoryBean">
	//	<!-- 调用服务端定义的服务 -->
	//	<property name="serviceUrl" value="http://localhost:8080/server/addService.htm" />
	//	<property name="serviceInterface" value="com.john.spring.hessian.server.AddService" />
	//	<!-- By default the value is false. As a matter of fact, it doesn't influence
	//the test result, the overloaded method still be supported -->
	//	<property name="overloadEnabled" value="false" />
	//</bean>

	/**
	 * 创建bean并且放入springBean工厂，取代xml的繁琐配置
	 * <p>
	 * 定义远程调用路由
	 * <bean name="/addService.htm" class="org.springframework.remoting.caucho.HessianServiceExporter">
	 * <property name="server" ref="addService"/>
	 * <property name="serviceInterface" value="com.john.spring.hessian.server.AddService"/>
	 * </bean>
	 * </p>
	 *
	 * @param context                   bean上下文
	 * @param hessianServiceImplRefBean serviceImpl--bean 的名称
	 * @param hessianServiceInterface   service的全类名
	 */
	private void registerBeanDefinition(ConfigurableApplicationContext context, String hessianServiceImplRefBean, String hessianServiceInterface) {
		// 通过BeanDefinitionBuilder创建bean定义
		BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(HessianProxyFactoryBean.class);
		// 设置属性userAcctDAO,此属性引用已经定义的bean:userAcctDAO
		beanDefinitionBuilder.addPropertyReference("serviceUrl", hessianServiceImplRefBean);
		beanDefinitionBuilder.addPropertyValue("serviceInterface", hessianServiceInterface);
		beanDefinitionBuilder.addPropertyValue("overloadEnabled", overloadEnabled);
		// 获取bean工厂并转换为DefaultListableBeanFactory
		DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) context.getBeanFactory();
		// 注册bean
		beanFactory.registerBeanDefinition(hessianServiceImplRefBean, beanDefinitionBuilder.getRawBeanDefinition());
	}

	public void setPrefix(String prefix) {
		this.prefix = prefix;
	}

	public void setAccessUrl(String accessUrl) {
		this.accessUrl = accessUrl;
	}

	public void setOverloadEnabled(boolean overloadEnabled) {
		this.overloadEnabled = overloadEnabled;
	}

	public void setSuffix(String suffix) {
		this.suffix = suffix;
	}

	public void setPackages(String[] packages) {
		this.packages = packages;
	}
}